#ifndef _UTILS_H
#define _UTILS_H

#include <iostream>
#include <vector>

using namespace std;

///////////////////////////////////////////////////////////////
typedef vector< char, allocator<char> > BYTE_vector;
///////////////////////////////////////////////////////////////
class ChunkStream
{
  public:
    ChunkStream() : first(0), last(0) {}

    int write(const void *pBuf, int count);
    int read(void *pBuf, int count);

  private:
    char data[256];
    int first;
    int last;

    ChunkStream *pNext;

  friend class ChunkStreamQ;
};
///////////////////////////////////////////////////////////////
class ChunkStreamQ
{
  public:
    ChunkStreamQ() : pFirst(NULL), pLast(NULL) {}

    void toQueue(ChunkStream *pChunk);
    ChunkStream *fromQueue();

    ChunkStream *first() { return pFirst; }
    ChunkStream *last() { return pLast; }

  private:
    ChunkStream *pFirst;
    ChunkStream *pLast;
};
///////////////////////////////////////////////////////////////
class DataStream
{
  public:
    DataStream(int _threshold = 0)
      : busy(0), threshold(_threshold), eof(false) {}
    ~DataStream() { DataStream::Clean(); }

    int PutData(const void *pBuf, int count);
    int GetData(void *pBuf, int count);
    void PutEof() { eof = true; }
    bool isFull() const { return threshold && threshold < busy; }
    void Clean();

  private:
    ChunkStreamQ bufQ;
    int busy;

    int threshold;
    bool eof;
};

///////////////////////////////////////////////////////////////
class Protocol
{
  public:
    Protocol(int _thresholdSend = 0, int _thresholdWrite = 0)
      : streamSendRead(_thresholdSend), streamWriteRecv(_thresholdWrite) {}

    virtual int Send(const void *pBuf, int count);
    int SendRaw(const void *pBuf, int count) { return streamSendRead.PutData(pBuf, count); }
    void SendEof() { streamSendRead.PutEof(); }
    bool isSendFull() const { return streamSendRead.isFull(); }
    int Read(void *pBuf, int count) { return streamSendRead.GetData(pBuf, count); }

    virtual int Write(const void *pBuf, int count);
    int WriteRaw(const void *pBuf, int count) { return streamWriteRecv.PutData(pBuf, count); }
    void WriteEof() { streamWriteRecv.PutEof(); }
    bool isWriteFull() const { return streamWriteRecv.isFull(); }
    int Recv(void *pBuf, int count) { return streamWriteRecv.GetData(pBuf, count); }
    virtual void Clean();

  private:
    DataStream streamSendRead;
    DataStream streamWriteRecv;
};

#endif
